{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 有关IPython系统的更多信息\n",
    "\n",
    "在第2章中，我们介绍了使用IPython Shell和Jupyter笔记本的基础知识。在本章中，我们探索了IPython系统中的一些更深层次的功能，这些功能可以从控制台或Jupyter中使用。\n",
    "\n",
    "## B.1 使用命令历史记录\n",
    "\n",
    "IPython维护着一个小的磁盘数据库，其中包含您执行的每个命令的文本。这有多种用途：\n",
    "\n",
    "- 以最少的输入量搜索，完成和执行先前执行的命令\n",
    "- 在会话之间保留命令历史记录\n",
    "- 将输入/输出历史记录到文件中\n",
    "\n",
    "这些功能在外壳中比在笔记本中有用，因为笔记本在设计上会记录每个代码单元中的输入和输出日志。\n",
    "\n",
    "### 搜索和重用命令历史记录\n",
    "\n",
    "IPython Shell使您可以搜索和执行先前的代码或其他命令。这很有用，因为您可能经常会发现自己重复相同的命令，例如％run命令或某些其他代码段。假设您已经运行：\n",
    "\n",
    "```sh\n",
    "    %run first/second/third/data_script.py\n",
    "```\n",
    "\n",
    "然后浏览脚本的结果（假设脚本已成功运行）只是发现您进行了错误的计算。解决问题并修改data_script.py之后，可以开始输入％run命令的几个字母，然后按Ctrl-P组合键或向上箭头键。这将在命令历史中搜索与您输入的字母匹配的第一个先前命令。多次按Ctrl-P或向上箭头键将继续搜索历史记录。如果您跳过要执行的命令，请不要担心。您可以通过按Ctrl-N或向下箭头键在命令历史记录中前进。这样做几次后，您可能会无意识地开始按这些键！\n",
    "\n",
    "使用Ctrl-R可为您提供由Unix风格的外壳（如bash外壳）中使用的readline提供的部分增量搜索功能。在Windows上，readline功能由IPython模拟。要使用此功能，请按Ctrl-R，然后输入要搜索的输入行中包含的几个字符：\n",
    "\n",
    "```python\n",
    "    a_command = foo(x, y, z)\n",
    "    \n",
    "    (reverse-i-search)`con': a_command = foo(x, y, z)\n",
    "```\n",
    "\n",
    "按Ctrl-R将在历史记录中循环显示与您键入的字符匹配的每一行。\n",
    "\n",
    "### 输入和输出变量\n",
    "\n",
    "忘记将函数调用的结果分配给变量可能会很烦人。IPython会话将对输入命令和输出Python对象的引用存储在特殊变量中。前两个输出分别存储在_（一个下划线）和__（两个下划线）变量中："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "134217728"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "2 ** 27"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "134217728"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "输入变量存储在名为_iX的变量中，其中X是输入行号。对于每个输入变量，都有一个对应的输出变量_X。因此，在输入行27之后，例如，将有两个新变量_27（用于输出）和_i27用于输入："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "foo = 'bar'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'bar'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "foo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'foo'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_i4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'bar'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "由于输入变量是字符串，因此可以使用Python exec关键字再次执行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "exec(_i4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "_i27指的是In [27]中输入的代码。\n",
    "\n",
    "几个魔术功能使您可以处理输入和输出历史记录。％hist可以打印全部或部分输入历史记录，带有或不带有行号。％reset用于清除交互式名称空间以及可选的输入和输出缓存。％xdel magic函数旨在从IPython机制中删除对特定对象的所有引用。有关更多详细信息，请参见有关这两种魔术的文档。\n",
    "\n",
    "> 注意：当处理非常大的数据集时，请记住，即使您使用del关键字从交互式名称空间中删除了变量，IPython的输入和输出历史记录也会导致对其中引用的任何对象都不会进行垃圾收集（释放内存）。在这种情况下，仔细使用％xdel和％reset可以帮助您避免遇到内存问题。\n",
    "\n",
    "## B.2 与操作系统进行交互\n",
    "\n",
    "IPython的另一个功能是，它允许您无缝访问文件系统和操作系统外壳。这意味着，除其他外，您可以执行大多数标准命令行操作，就像在Windows或Unix（Linux，macOS）Shell中一样，而不必退出IPython。这包括Shell命令，更改目录以及将命令结果存储在Python对象（列表或字符串）中。还有简单的命令别名和目录书签功能。\n",
    "\n",
    "有关调用Shell命令的魔术函数和语法的摘要，请参见表B-1。在接下来的几节中，我将简要介绍这些功能。\n",
    "\n",
    "### Shell命令和别名\n",
    "\n",
    "在IPython中以感叹号！或bang开头的行告诉IPython在系统外壳中的bang之后执行所有操作。 这意味着您可以删除文件（使用rm或del，具体取决于您的操作系统），更改目录或执行任何其他过程。\n",
    "\n",
    "您可以通过分配用！转义的表达式来将shell命令的控制台输出存储在变量中。到一个变量。 例如，在通过以太网连接到互联网的基于Linux的计算机上，我可以将我的IP地址作为Python变量获取："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "ip_info = !ifconfig en0 | grep \"inet \""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'inet 192.168.0.104 netmask 0xffffff00 broadcast 192.168.0.255'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ip_info[0].strip()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "返回的Python对象ip_info实际上是一个自定义列表类型，其中包含各种版本的控制台输出。\n",
    "\n",
    "使用！时，IPython还可以替换当前环境中定义的Python值。为此，请在变量名前加上美元符号$："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "foo = 'test*'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "test.py\r\n"
     ]
    }
   ],
   "source": [
    "!ls $foo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "％alias magic函数可以为Shell命令定义自定义快捷方式。作为一个简单的例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "%alias ll ls -l"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "total 0\r\n",
      "lrwxr-xr-x     1 root  wheel     25 10 16  2019 \u001b[35mX11\u001b[m\u001b[m -> ../private/var/select/X11\r\n",
      "lrwxr-xr-x     1 root  wheel     25 10 16  2019 \u001b[35mX11R6\u001b[m\u001b[m -> ../private/var/select/X11\r\n",
      "drwxr-xr-x  1014 root  wheel  32448  6  8 19:35 \u001b[1m\u001b[36mbin\u001b[m\u001b[m\r\n",
      "drwxr-xr-x   312 root  wheel   9984  6  8 19:39 \u001b[1m\u001b[36mlib\u001b[m\u001b[m\r\n",
      "drwxr-xr-x   264 root  wheel   8448  6  8 19:35 \u001b[1m\u001b[36mlibexec\u001b[m\u001b[m\r\n",
      "drwxr-xr-x    22 root  wheel    704  6  8 19:38 \u001b[1m\u001b[36mlocal\u001b[m\u001b[m\r\n",
      "drwxr-xr-x   234 root  wheel   7488  6  8 19:35 \u001b[1m\u001b[36msbin\u001b[m\u001b[m\r\n",
      "drwxr-xr-x    46 root  wheel   1472 10 16  2019 \u001b[1m\u001b[36mshare\u001b[m\u001b[m\r\n",
      "drwxr-xr-x     5 root  wheel    160  9 30  2019 \u001b[1m\u001b[36mstandalone\u001b[m\u001b[m\r\n"
     ]
    }
   ],
   "source": [
    "ll /usr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "您可以像在命令行上一样执行多个命令，方法是使用分号将它们分开："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "%alias test_alias (cd examples; ls; cd ..)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "csv_mindex.csv             fdic_failed_bank_list.html\r\n",
      "ex1.csv                    frame_pickle\r\n",
      "ex1.xlsx                   ipython_bug.py\r\n",
      "ex2.csv                    ipython_bug2.py\r\n",
      "ex2.xlsx                   macrodata.csv\r\n",
      "ex3.txt                    out.csv\r\n",
      "ex4.csv                    segismundo.txt\r\n",
      "ex5.csv                    spx.csv\r\n",
      "ex6.csv                    stock_px_2.csv\r\n",
      "ex7.csv                    tips.csv\r\n",
      "example.json               tseries.csv\r\n"
     ]
    }
   ],
   "source": [
    "test_alias"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "您会注意到，一旦关闭会话，IPython就会“忘记”您以交互方式定义的任何别名。要创建永久别名，您将需要使用配置系统。\n",
    "\n",
    "### 目录书签系统\n",
    "\n",
    "IPython有一个简单的目录书签系统，使您能够保存常用目录的别名，以便您可以轻松地跳转。例如，假设您想创建一个书签，指向该书的补充材料："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "%bookmark py4da /Users/gaussic/projects/pydata2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "完成此操作后，当我们使用％cd魔术时，我们可以使用定义的所有书签："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(bookmark:py4da) -> /Users/gaussic/projects/pydata2\n",
      "/Users/gaussic/Projects/pydata2\n"
     ]
    }
   ],
   "source": [
    "cd py4da"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果书签名称与当前工作目录中的目录名称冲突，则可以使用-b标志覆盖并使用书签位置。将-l选项与％bookmark一起使用会列出所有书签："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Current bookmarks:\n",
      "py4da -> /Users/gaussic/projects/pydata2\n"
     ]
    }
   ],
   "source": [
    "%bookmark -l"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "与别名不同，书签在IPython会话之间自动保留。\n",
    "\n",
    "## B.3 软件开发工具\n",
    "\n",
    "除了为交互式计算和数据探索提供舒适的环境外，IPython还可作为常规Python软件开发的有用伴侣。在数据分析应用中，重要的是首先要拥有正确的代码。幸运的是，IPython已经紧密集成并增强了内置的Python pdb调试器。其次，您希望您的代码更快。为此，IPython提供了易于使用的代码计时和性能分析工具。我将在这里详细介绍这些工具。\n",
    "\n",
    "### 交互式调试器\n",
    "\n",
    "IPython的调试器通过选项卡补全，语法突出显示和异常回溯中每一行的上下文来增强pdb。发生错误后，立即调试代码的最佳时间之一。在发生异常后立即输入％debug命令时，它会调用“事后检验”调试器，并将您放入引发异常的堆栈帧中："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "ename": "AssertionError",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAssertionError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m~/Projects/pydata2/examples/ipython_bug.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     13\u001b[0m     \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m~/Projects/pydata2/examples/ipython_bug.py\u001b[0m in \u001b[0;36mcalling_things\u001b[0;34m()\u001b[0m\n\u001b[1;32m     11\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     12\u001b[0m     \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m     \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     15\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/Projects/pydata2/examples/ipython_bug.py\u001b[0m in \u001b[0;36mthrows_an_exception\u001b[0;34m()\u001b[0m\n\u001b[1;32m      7\u001b[0m     \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m     \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m     \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mAssertionError\u001b[0m: "
     ]
    }
   ],
   "source": [
    "%run examples/ipython_bug.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(9)\u001b[0;36mthrows_an_exception\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m      7 \u001b[0;31m    \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      8 \u001b[0;31m    \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m----> 9 \u001b[0;31m    \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     10 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> u\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(13)\u001b[0;36mcalling_things\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     12 \u001b[0;31m    \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m---> 13 \u001b[0;31m    \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     14 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     15 \u001b[0;31m\u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> q\n"
     ]
    }
   ],
   "source": [
    "%debug"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "进入调试器后，您可以执行任意Python代码，并探索每个堆栈框架内的所有对象和数据（已由解释器“保留”）。默认情况下，您从发生错误的最低级别开始。通过按u（向上）和d（向下），您可以在堆栈跟踪级别之间切换：\n",
    "\n",
    "执行％pdb命令可以使IPython在发生任何异常后自动调用调试器，这种模式许多用户会发现它特别有用。\n",
    "\n",
    "使用调试器来帮助开发代码也很容易，尤其是当您希望设置断点或逐步执行函数或脚本以检查每个阶段的状态时，尤其如此。有几种方法可以完成此操作。第一种是将％run与-d标志一起使用，该标志在执行传递的脚本中的任何代码之前调用调试器。您必须立即按s（步骤）以输入脚本："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Breakpoint 1 at /Users/gaussic/Projects/pydata2/examples/ipython_bug.py:1\n",
      "NOTE: Enter 'c' at the ipdb>  prompt to continue execution.\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(1)\u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n",
      "\u001b[1;31m1\u001b[0;32m---> 1 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      2 \u001b[0;31m    \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      3 \u001b[0;31m    \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      4 \u001b[0;31m    \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      5 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> s\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(6)\u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m      4 \u001b[0;31m    \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      5 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m----> 6 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      7 \u001b[0;31m    \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      8 \u001b[0;31m    \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> q\n"
     ]
    }
   ],
   "source": [
    "run -d examples/ipython_bug.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在这之后，由您决定如何处理文件。例如，在前面的异常中，我们可以在调用works_fine方法之前设置断点，然后运行脚本，直到我们按c到达断点为止（继续）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Breakpoint 1 at /Users/gaussic/Projects/pydata2/examples/ipython_bug.py:1\n",
      "NOTE: Enter 'c' at the ipdb>  prompt to continue execution.\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(1)\u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n",
      "\u001b[1;31m1\u001b[0;32m---> 1 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      2 \u001b[0;31m    \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      3 \u001b[0;31m    \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      4 \u001b[0;31m    \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      5 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> b 12\n",
      "Breakpoint 2 at /Users/gaussic/Projects/pydata2/examples/ipython_bug.py:12\n",
      "ipdb> c\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(12)\u001b[0;36mcalling_things\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m     10 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m2\u001b[0;32m--> 12 \u001b[0;31m    \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     13 \u001b[0;31m    \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     14 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> n\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(13)\u001b[0;36mcalling_things\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m2\u001b[0;32m    12 \u001b[0;31m    \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m---> 13 \u001b[0;31m    \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     14 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     15 \u001b[0;31m\u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> \n",
      "AssertionError\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(13)\u001b[0;36mcalling_things\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m2\u001b[0;32m    12 \u001b[0;31m    \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m---> 13 \u001b[0;31m    \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     14 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     15 \u001b[0;31m\u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> q\n"
     ]
    }
   ],
   "source": [
    "run -d examples/ipython_bug.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此时，您可以进入works_fine（）或通过按n（下一页）前进到下一行来执行works_fine（）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Breakpoint 1 at /Users/gaussic/Projects/pydata2/examples/ipython_bug.py:1\n",
      "NOTE: Enter 'c' at the ipdb>  prompt to continue execution.\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(1)\u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n",
      "\u001b[1;31m1\u001b[0;32m---> 1 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      2 \u001b[0;31m    \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      3 \u001b[0;31m    \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      4 \u001b[0;31m    \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      5 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> b 12\n",
      "Breakpoint 2 at /Users/gaussic/Projects/pydata2/examples/ipython_bug.py:12\n",
      "ipdb> c\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(12)\u001b[0;36mcalling_things\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m     10 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m2\u001b[0;32m--> 12 \u001b[0;31m    \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     13 \u001b[0;31m    \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     14 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> n\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(13)\u001b[0;36mcalling_things\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m2\u001b[0;32m    12 \u001b[0;31m    \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m---> 13 \u001b[0;31m    \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     14 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     15 \u001b[0;31m\u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> n\n",
      "AssertionError\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(13)\u001b[0;36mcalling_things\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m2\u001b[0;32m    12 \u001b[0;31m    \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m---> 13 \u001b[0;31m    \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     14 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     15 \u001b[0;31m\u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> n\n",
      "--Return--\n",
      "None\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(13)\u001b[0;36mcalling_things\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m2\u001b[0;32m    12 \u001b[0;31m    \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m---> 13 \u001b[0;31m    \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     14 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     15 \u001b[0;31m\u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> !a\n",
      "*** NameError: name 'a' is not defined\n",
      "ipdb> n\n",
      "AssertionError\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(15)\u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m2\u001b[0;32m    12 \u001b[0;31m    \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     13 \u001b[0;31m    \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     14 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m---> 15 \u001b[0;31m\u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> n\n",
      "--Return--\n",
      "None\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(15)\u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m     11 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m2\u001b[0;32m    12 \u001b[0;31m    \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     13 \u001b[0;31m    \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m     14 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m---> 15 \u001b[0;31m\u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> n\n",
      "AssertionError\n",
      "> \u001b[0;32m/Users/gaussic/opt/anaconda3/lib/python3.7/site-packages/IPython/utils/py3compat.py\u001b[0m(188)\u001b[0;36mexecfile\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m    186 \u001b[0;31m    \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'rb'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m    187 \u001b[0;31m        \u001b[0mcompiler\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcompiler\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mcompile\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m--> 188 \u001b[0;31m        \u001b[0mexec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcompiler\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'exec'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mglob\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mloc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m    189 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m    190 \u001b[0;31m\u001b[0;31m# Refactor print statements in doctests.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> q\n"
     ]
    }
   ],
   "source": [
    "run -d examples/ipython_bug.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然后，我们可以进入throws_an_exception并前进到发生错误的行，并查看范围中的变量。注意调试器命令优先于变量名；在这种情况下，请在变量前加!！ 检查它们的内容："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Breakpoint 1 at /Users/gaussic/Projects/pydata2/examples/ipython_bug.py:1\n",
      "NOTE: Enter 'c' at the ipdb>  prompt to continue execution.\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(1)\u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n",
      "\u001b[1;31m1\u001b[0;32m---> 1 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      2 \u001b[0;31m    \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      3 \u001b[0;31m    \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      4 \u001b[0;31m    \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      5 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> q\n"
     ]
    }
   ],
   "source": [
    "run -d examples/ipython_bug.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用交互式调试器来提高熟练程度在很大程度上取决于实践和经验。有关调试器命令的完整目录，请参见表B-2。如果您习惯于使用IDE，则可能会发现终端驱动的调试器起初有点让人难以原谅，但随着时间的推移会有所改善。一些Python IDE具有出色的GUI调试器，因此大多数用户可以找到适合他们的东西。\n",
    "\n",
    "#### 其他使用调试器的方式\n",
    "\n",
    "还有其他两种有用的方法来调用调试器。第一种是使用特殊的set_trace函数（以pdb.set_trace命名），该函数基本上是“穷人的断点”。您可以将以下两个小食谱放到某个地方以供一般使用（有可能像我一样将它们添加到您的IPython配置文件中）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.debugger import Pdb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "def set_trace():\n",
    "    Pdb(color_schema='Linux').set_trace(sys._getframe().f_back)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "def debug(f, *args, **kwargs):\n",
    "    pdb = Pdb(color_schema='Linux')\n",
    "    return pdb.runcall(f, *args, **kwargs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第一个函数set_trace非常简单。您可以在要暂时停止的代码的任何部分中使用set_trace，以便更仔细地检查它（例如，在发生异常之前）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "ename": "AssertionError",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAssertionError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m~/Projects/pydata2/examples/ipython_bug.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     13\u001b[0m     \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m~/Projects/pydata2/examples/ipython_bug.py\u001b[0m in \u001b[0;36mcalling_things\u001b[0;34m()\u001b[0m\n\u001b[1;32m     11\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     12\u001b[0m     \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m     \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     15\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/Projects/pydata2/examples/ipython_bug.py\u001b[0m in \u001b[0;36mthrows_an_exception\u001b[0;34m()\u001b[0m\n\u001b[1;32m      7\u001b[0m     \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m     \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m     \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcalling_things\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mAssertionError\u001b[0m: "
     ]
    }
   ],
   "source": [
    "run examples/ipython_bug.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "按下c（继续）将使代码正常恢复而不会造成伤害。\n",
    "\n",
    "我们刚刚查看的调试功能使您可以在任意函数调用上轻松调用交互式调试器。 假设我们编写了如下函数，并希望逐步了解它的逻辑："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x, y, z=1):\n",
    "    tmp = x + y\n",
    "    return tmp / z"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通常使用f看起来像f（1，2，z = 3）。 要改为进入f，请传递f作为要调试的第一个参数，然后传递要传递给f的position和keyword参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "__init__() got an unexpected keyword argument 'color_schema'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-34-0fe32856319a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdebug\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mz\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-31-a8c826934aa5>\u001b[0m in \u001b[0;36mdebug\u001b[0;34m(f, *args, **kwargs)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdebug\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m     \u001b[0mpdb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPdb\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcolor_schema\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'Linux'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m     \u001b[0;32mreturn\u001b[0m \u001b[0mpdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mruncall\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/IPython/core/debugger.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, color_scheme, completekey, stdin, stdout, context, **kwargs)\u001b[0m\n\u001b[1;32m    228\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    229\u001b[0m         \u001b[0;31m# `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 230\u001b[0;31m         \u001b[0mOldPdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcompletekey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstdin\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstdout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    231\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    232\u001b[0m         \u001b[0;31m# IPython changes...\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mTypeError\u001b[0m: __init__() got an unexpected keyword argument 'color_schema'"
     ]
    }
   ],
   "source": [
    "debug(f, 1, 2, z=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我发现这两个简单的食谱每天为我节省了大量时间。\n",
    "\n",
    "最后，调试器可以与％run结合使用。 通过使用％run -d运行脚本，您将直接进入调试器，可以设置任何断点并启动脚本："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Breakpoint 1 at /Users/gaussic/Projects/pydata2/examples/ipython_bug.py:1\n",
      "NOTE: Enter 'c' at the ipdb>  prompt to continue execution.\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(1)\u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n",
      "\u001b[1;31m1\u001b[0;32m---> 1 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      2 \u001b[0;31m    \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      3 \u001b[0;31m    \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      4 \u001b[0;31m    \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      5 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> s\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(6)\u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m      4 \u001b[0;31m    \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      5 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m----> 6 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mthrows_an_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      7 \u001b[0;31m    \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      8 \u001b[0;31m    \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> q\n"
     ]
    }
   ],
   "source": [
    "%run -d examples/ipython_bug.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在行号后加上-b可以启动调试器并设置断点："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Breakpoint 1 at /Users/gaussic/Projects/pydata2/examples/ipython_bug.py:2\n",
      "NOTE: Enter 'c' at the ipdb>  prompt to continue execution.\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(1)\u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m----> 1 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m1\u001b[0;32m     2 \u001b[0;31m    \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      3 \u001b[0;31m    \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      4 \u001b[0;31m    \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      5 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> c\n",
      "> \u001b[0;32m/Users/gaussic/Projects/pydata2/examples/ipython_bug.py\u001b[0m(2)\u001b[0;36mworks_fine\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;32m      1 \u001b[0;31m\u001b[0;32mdef\u001b[0m \u001b[0mworks_fine\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[1;31m1\u001b[0;32m---> 2 \u001b[0;31m    \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      3 \u001b[0;31m    \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      4 \u001b[0;31m    \u001b[0;32massert\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m11\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\u001b[0;32m      5 \u001b[0;31m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0m\n",
      "ipdb> q\n"
     ]
    }
   ],
   "source": [
    "%run -d -b2 examples/ipython_bug.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 时间码：％time和％timeit\n",
    "\n",
    "对于大型或更长时间运行的数据分析应用程序，您可能希望测量各种组件或单个语句或函数调用的执行时间。 您可能需要一份报告，说明在复杂过程中哪些功能占用最多的时间。 幸运的是，在开发和测试代码时，IPython使您能够非常轻松地获取此信息。\n",
    "\n",
    "使用内置的时间模块及其功能time.clock和time.time手动计时代码通常是乏味且重复的，因为您必须编写相同的有趣的样板代码：\n",
    "\n",
    "```python \n",
    "import time\n",
    "start = time.time()\n",
    "for i in range(iterations):\n",
    "    # some code to run hera\n",
    "    elapsed_per = (time.time() - start) / iterations\n",
    "```\n",
    "\n",
    "由于这是一种常见的操作，因此IPython具有两个魔术函数％time和％timeit，可以为您自动执行此过程。\n",
    "\n",
    "％time运行一次语句，报告总执行时间。 假设我们有很多字符串，我们想比较选择以特定前缀开头的所有字符串的不同方法。 这是600,000个字符串的简单列表，以及两种相同的方法，仅选择以'foo'开头的字符串："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "# a very large of strings\n",
    "strings = ['foo', 'foobar', 'baz', 'qux', 'python', 'Guido Van Rossum'] * 100000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "method1 = [x for x in strings if x.startswith('foo')]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "method2 = [x for x in strings if x[:3] == 'foo']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "看起来他们应该在性能上差不多，对吧？ 我们可以使用％time来检查："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 108 ms, sys: 4.56 ms, total: 113 ms\n",
      "Wall time: 120 ms\n"
     ]
    }
   ],
   "source": [
    "%time method1 = [x for x in strings if x.startswith('foo')]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 101 ms, sys: 5.11 ms, total: 106 ms\n",
      "Wall time: 128 ms\n"
     ]
    }
   ],
   "source": [
    "%time method2 = [x for x in strings if x[:3] == 'foo']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "主要时间是Wall时间（“ wall-clock time”的缩写）。 因此，第一种方法似乎花费了两倍多的时间，但这并不是一种非常精确的测量方法。 如果您多次尝试对这些语句进行％timeing操作，则会发现结果有些变化。 要获得更精确的测量，请使用％timeit魔术功能。 给定一个任意语句，它可以试探多次运行一条语句以产生更准确的平均运行时间："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "108 ms ± 9.17 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit [x for x in strings if x.startswith('foo')]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "83.2 ms ± 14.4 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit [x for x in strings if x[:3] == 'foo']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个看似无害的示例说明，值得理解Python标准库，NumPy，pandas和本书中使用的其他库的性能特征。在大型数据分析应用程序中，这些毫秒数将开始累加！\n",
    "\n",
    "％timeit对于分析执行时间非常短的语句和函数特别有用，即使是在微秒（百万分之一秒）或纳秒（十亿分之一秒）的水平上。 这些时间看似微不足道，但是当然，调用1百万次的20微秒函数比5微秒函数要花15秒的时间。 在前面的示例中，我们可以非常直接地比较两个字符串操作以了解它们的性能特征："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 'foobar'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "y = 'foo'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "174 ns ± 3.16 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit x.startswith(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "143 ns ± 4.25 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit x[:3] == y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 基本配置文件：％prun和％run -p\n",
    "\n",
    "概要分析代码与时序代码紧密相关，但它与确定时间花费在哪里有关。Python的主要分析工具是cProfile模块，它根本不是特定于IPython的。cProfile执行一个程序或任意代码块，同时跟踪每个功能花费了多少时间。\n",
    "\n",
    "使用cProfile的一种常见方法是在命令行上，运行整个程序并输出每个函数的累计时间。假设我们有一个简单的脚本，它可以在循环中进行一些线性代数运算（计算一系列100×100矩阵的最大绝对特征值）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "from numpy.linalg import eigvals"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "def run_experiment(niter=100):\n",
    "    K = 100\n",
    "    results = []\n",
    "    for _ in range(niter):\n",
    "        mat = np.random.randn(K, K)\n",
    "        max_eigenvalue = np.abs(eigvals(mat)).max()\n",
    "        results.append(max_eigenvalue)\n",
    "    return results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "some_results = run_experiment()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Largest one we saw: 11.551311243370492'"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'Largest one we saw: %s' % np.max(some_results)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "您可以在命令行中使用以下命令通过cProfile运行此脚本：\n",
    "\n",
    "```sh\n",
    "python -m cProfile cprof_example.ly\n",
    "```\n",
    "\n",
    "如果您尝试这样做，则会发现输出是按函数名称排序的。 这使您很难了解最多的时间在哪里，因此使用-s标志指定排序顺序是很常见的：\n",
    "\n",
    "```sh\n",
    "$ python -m cProfile -s cumulative cprof_example.py\n",
    "```\n",
    "\n",
    "仅显示输出的前15行。向下浏览cumtime列以查看每个功能花费了多少时间，这是最容易阅读的内容。请注意，如果一个函数调用其他函数，则时钟不会停止运行。cProfile记录每个函数调用的开始和结束时间，并使用该时间来产生计时。\n",
    "\n",
    "除了命令行用法外，cProfile还可以通过编程方式用于配置任意代码块，而不必运行新的进程。IPython使用％prun命令和％run的-p选项为该功能提供了方便的接口。％prun使用与cProfile相同的“命令行选项”，但将分析任意Python语句而不是整个.py文件："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    }
   ],
   "source": [
    "%prun -l 7 -s cumulative run_experiment()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同样，调用％run -p -scumulative cprof_example.py与命令行方法具有相同的效果，除了不必离开IPython。\n",
    "\n",
    "在Jupyter笔记本中，您可以使用%% prun魔术（两个％符号）来分析整个代码块。 这会弹出一个带有配置文件输出的单独窗口。 这对于快速回答以下问题可能很有用：“为什么该代码块要花这么长时间才能运行？”\n",
    "\n",
    "还有其他工具可帮助您在使用IPython或Jupyter时使配置文件更容易理解。 SnakeViz就是其中之一，它使用d3.js对配置文件结果进行交互式可视化。\n",
    "\n",
    "### 逐行分析功能\n",
    "\n",
    "在某些情况下，您从％prun（或其他基于cProfile的配置文件方法）获得的信息可能无法完整说明函数的执行时间，或者它可能太复杂以至于难以解释按函数名称汇总的结果 在这种情况下，有一个名为line_profiler的小型库（可通过PyPI或软件包管理工具之一获得）。 它包含一个IPython扩展，该扩展启用了一个新的魔术函数％lprun，该魔术函数可计算一个或多个函数的逐行分析。 您可以通过修改IPython配置（请参阅IPython文档或本章稍后的配置部分）以包括以下行来启用此扩展:\n",
    "\n",
    "```python\n",
    "# A list of dotted module names of IPython extensions to load.\n",
    "c.TerminalIPythonApp.extensions = ['line_profiler']\n",
    "```\n",
    "\n",
    "您还可以运行以下命令：\n",
    "\n",
    "```python\n",
    "%load_ext line_profile\n",
    "```\n",
    "\n",
    "line_profiler可以通过编程方式使用（请参阅完整文档），但是在IPython中以交互方式使用时，它可能是最强大的。 假设您有一个模块prof_mod，其中的以下代码执行了一些NumPy数组操作："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "from numpy.random import randn\n",
    "\n",
    "def add_and_sum(x, y):\n",
    "    added = x + y\n",
    "    summed = added.sum(axis=1)\n",
    "    return summed\n",
    "\n",
    "def call_function():\n",
    "    x = randn(1000, 1000)\n",
    "    y = randn(1000, 1000)\n",
    "    return add_and_sum(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果我们想了解add_and_sum函数的性能，％prun为我们提供以下内容："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run prof_mod"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = randn(3000, 3000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "y = randn(3000, 3000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    }
   ],
   "source": [
    "%prun add_and_sum(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这不是特别有启发性。 激活line_profiler IPython扩展后，新命令％lprun可用。 用法的唯一区别是，我们必须指示％lprun我们要分析的功能。 通用语法为：\n",
    "\n",
    "```python\n",
    "%lprun -f func1 -f func2 statement_to_profile\n",
    "```\n",
    "\n",
    "在这种情况下，我们要分析add_and_sum，因此我们运行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "UsageError: Line magic function `%lprun` not found.\n"
     ]
    }
   ],
   "source": [
    "%lprun -f add_and_sum add_and_sum(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这可能更容易解释。 在这种情况下，我们分析了该语句中使用的相同功能。查看前面的模块代码，我们可以调用call_function和profile以及add_and_sum，从而获得代码性能的全貌："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "UsageError: Line magic function `%lprun` not found.\n"
     ]
    }
   ],
   "source": [
    "%lprun -f add_and_sum -f call_function call_function()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "根据一般经验，我倾向于将％prun（cProfile）用于“宏”分析，而将％lprun（line_profiler）用于“微”分析。 充分了解这两种工具是值得的。\n",
    "\n",
    "> 必须使用％lprun明确指定要分析的函数名称的原因是，“跟踪”每行的执行时间会产生大量开销。 不需要的跟踪功能可能会显着更改配置文件结果。\n",
    "\n",
    "## B.4 使用IPython进行生产代码开发的技巧\n",
    "\n",
    "对于许多用户来说，以易于开发，调试和最终以交互方式使用的方式编写代码可能是一种范式转变。 有一些过程细节，例如代码重新加载，可能需要进行一些调整以及对编码样式的关注。\n",
    "\n",
    "因此，实施本节中描述的大多数策略更多的是艺术而不是科学，并且需要您做一些实验来确定编写对您有效的Python代码的方法。 最终，您希望以一种易于迭代操作的方式来构造代码，并能够尽可能轻松地探索运行程序或函数的结果。 我发现考虑到IPython设计的软件比仅作为独立的命令行应用程序运行的代码更易于使用。 当出现问题并且必须诊断您或其他人可能事先写了几个月或几年的代码错误时，这一点尤其重要。\n",
    "\n",
    "### 重新加载模块依赖项\n",
    "\n",
    "在Python中，当您输入import some_lib时，将执行some_lib中的代码，并将其中定义的所有变量，函数和导入存储在新创建的some_lib模块命名空间中。 下次键入import some_lib时，将获得对现有模块名称空间的引用。 例如，如果您运行一个脚本，该脚本依赖于您可能已进行更改的某些其他模块，则可能会产生交互式IPython代码开发的潜在困难。 假设我在test_script.py中有以下代码：\n",
    "\n",
    "```python\n",
    "    import some_lib\n",
    "\n",
    "    x = 5\n",
    "    y = [1, 2, 3, 4]\n",
    "    result = some_lib.get_answer(x, y)\n",
    "```\n",
    "\n",
    "如果您要执行％run test_script.py，然后修改some_lib.py，则下次执行％run test_script.py时，由于Python的“一次加载”模块系统，您仍将获得some_lib.py的旧版本。 此行为与其他一些数据分析环境（例如MATLAB）不同，后者会自动传播代码更改。为解决此问题，您有两个选择。 第一种方法是在标准库的importlib模块中使用reload函数：\n",
    "\n",
    "```python\n",
    "    import some_lib\n",
    "    import importlib\n",
    "    \n",
    "    importlib.reload(some_lib)\n",
    "```\n",
    "\n",
    "这样可以确保您每次运行test_script.py时都会获得some_lib.py的新副本。显然，如果依赖关系更深，那么在各处插入重载用法可能会有些棘手。对于这个问题，IPython具有特殊的dreload函数（不是魔术函数），用于“深度”（递归）模块重载。 如果我要运行some_lib.py，然后输入dreload（some_lib），它将尝试重新加载some_lib及其所有依赖项。 不幸的是，这并非在所有情况下都有效，但是这样做时，必须重新启动IPython。\n",
    "\n",
    "### 代码设计技巧\n",
    "\n",
    "这没有简单的秘方，但是这里有一些我发现对自己的工作有效的高级原则。\n",
    "\n",
    "#### 使相关对象和数据保持活动状态\n",
    "\n",
    "看到一个为命令行编写的程序具有类似以下普通示例的结构是很正常的：\n",
    "\n",
    "```python\n",
    "    from my_functions import g\n",
    "    \n",
    "    def f(x, y):\n",
    "        return g(x + y)\n",
    "    \n",
    "    def main():\n",
    "        x = 6\n",
    "        y = 7.5\n",
    "        result = x + y\n",
    "        \n",
    "    if __name__ == '__main__':\n",
    "        main()\n",
    "```\n",
    "\n",
    "您是否看到如果我们在IPython中运行该程序可能会出问题？ 完成后，将无法在IPython Shell中访问main函数中定义的任何结果或对象。 更好的方法是让main中的所有代码直接在模块的全局命名空间中执行（或者，如果您希望模块也可导入，则在if __name__ =='__main__'：块中执行）。 这样，当您％运行代码时，便可以查看main中定义的所有变量。 这等效于在Jupyter笔记本中的单元格中定义顶级变量。\n",
    "\n",
    "#### 扁平比嵌套更好\n",
    "\n",
    "深度嵌套的代码使我想到了洋葱的许多层。在测试或调试功能时，必须剥开洋葱的几层才能到达所需的代码？“扁平比嵌套更好”的想法是Python Zen的一部分，并且通常也适用于开发用于交互使用的代码。使函数和类尽可能地分离和模块化，使它们更易于测试（如果您正在编写单元测试），调试和交互使用。\n",
    "\n",
    "#### 克服对更长文件的恐惧\n",
    "\n",
    "如果您来自Java（或其他类似语言）背景，则可能已被告知要使文件简短。在许多语言中，这是合理的建议。长的长度通常是一种不好的“代码气味”，表明可能需要进行重构或重组。 但是，在使用IPython开发代码时，与两个或三个较长的文件相比，使用10个较小但相互连接的文件（每个文件在100行以下）可能会给您带来更多的麻烦。 文件越少，意味着要重新加载的模块越少，编辑时文件之间的跳转也越少。 我发现维护较大的模块（每个模块都具有较高的内部凝聚力）会变得更加有用和Pythonic。 在寻求解决方案之后，有时将大型文件重构为较小的文件是有意义的。\n",
    "\n",
    "显然，我不支持将这种说法推得太高，那是将所有代码都放在一个单一的可怕文件中。为大型代码库找到一个明智而直观的模块和包结构通常需要花费一些工作，但是正确地团队协作尤为重要。每个模块应该在内部具有内聚性，并且应该尽可能地清楚地找到负责每个功能领域的函数和类。\n",
    "\n",
    "## B.5 IPython的高级功能\n",
    "\n",
    "充分利用IPython系统可能会导致您以略有不同的方式编写代码，或深入研究配置。\n",
    "\n",
    "### 使自己的类对IPython友好\n",
    "\n",
    "IPython竭尽全力显示您检查的任何对象的控制台友好的字符串表示形式。 对于许多对象，如字典，列表和元组，内置的pprint模块用于进行漂亮的格式化。 但是，在用户定义的类中，您必须自己生成所需的字符串输出。 假设我们有以下简单的类:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Message:\n",
    "    def __init__(self, msg):\n",
    "        self.msg = msg"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果您写了这段文字，您会发现您类的默认输出不是很好而感到失望："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = Message('I have a secret')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.Message at 0x7fc82519b790>"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "IPython接受__repr__魔术方法返回的字符串（通过执行output = repr（obj））并将其打印到控制台。因此，我们可以在前面的类中添加一个简单的__repr__方法以获得更有用的输出："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Message:\n",
    "    def __init__(self, msg):\n",
    "        self.msg = msg\n",
    "        \n",
    "    def __repr__(self):\n",
    "        return 'Message: %s' % self.msg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = Message('I have a secret')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Message: I have a secret"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 配置文件和配置\n",
    "\n",
    "IPython和Jupyter环境的外观的大多数方面（颜色，提示，行间距等）和行为都可以通过广泛的配置系统进行配置。 您可以通过配置执行以下操作：\n",
    "\n",
    "- 更改配色方案\n",
    "- 更改输入和输出提示的外观，或在Out之后和下一个In提示之前删除空白行\n",
    "- 执行任意的Python语句列表（例如，您一直使用的导入或每次启动IPython时想要发生的其他事情）\n",
    "- 启用永远在线的IPython扩展，例如line_profiler中的％lprun魔术\n",
    "- 启用Jupyter扩展\n",
    "- 定义自己的魔术或系统别名\n",
    "\n",
    "在特殊的ipython_config.py文件中指定了IPython Shell的配置，这些文件通常位于用户主目录的.ipython /目录中。 配置是基于特定的配置文件执行的。 正常启动IPython时，默认情况下会加载存储在profile_default目录中的默认配置文件。 因此，在我的Linux操作系统上，默认IPython配置文件的完整路径为：\n",
    "\n",
    "```sh\n",
    "    /home/wesm/.ipython/profile_default/ipython_config.py\n",
    "```\n",
    "\n",
    "要在系统上初始化此文件，请在终端中运行：\n",
    "\n",
    "```sh\n",
    "    ipython profile create\n",
    "```\n",
    "\n",
    "我将为您提供有关此文件内容的详细信息。幸运的是，它的注释描述了每个配置选项的用途，因此我将留给读者自己修改和定制。 另一个有用的功能是可以有多个配置文件。 假设您想为特定的应用程序或项目量身定制其他IPython配置。 创建新的配置文件就像输入以下内容一样简单：\n",
    "\n",
    "```sh\n",
    "    ipython profile create secret_project\n",
    "```\n",
    "\n",
    "完成此操作后，请在新创建的profile_secret_project目录中编辑配置文件，然后按以下方式启动IPython：\n",
    "\n",
    "```sh\n",
    "$ ipython --profile=secret_project\n",
    "Python 3.5.1 | packaged by conda-forge | (default, May 20 2016, 05:22:56)\n",
    "Type \"copyright\", \"credits\" or \"license\" for more information.\n",
    "IPython 5.1.0 -- An enhanced Interactive Python.\n",
    "? -> Introduction and overview of IPython's features.\n",
    "%quickref -> Quick reference.\n",
    "help -> Python's own help system.\n",
    "object? -> Details about 'object', use 'object??' for extra details.\n",
    "IPython profile: secret_project\n",
    "```\n",
    "\n",
    "与往常一样，在线IPython文档是有关配置文件和配置的更多内容的绝佳资源。\n",
    "\n",
    "Jupyter的配置工作有所不同，因为您可以将其笔记本与Python以外的其他语言一起使用。要创建类似的Jupyter配置文件，请运行：\n",
    "\n",
    "```sh\n",
    "jupyter notebook --generate-config\n",
    "```\n",
    "\n",
    "这会将默认配置文件写入主目录中的.jupyter / jupyter_notebook_config.py目录。 根据需要编辑此文件后，可以将其重命名为其他文件，例如：\n",
    "\n",
    "```sh\n",
    "$ mv ~/.jupyter/jupyter_notebook_config.py ~/.jupyter/my_custom_config.py\n",
    "```\n",
    "\n",
    "启动Jupyter时，可以添加--config参数：\n",
    "\n",
    "```sh\n",
    "jupyter notebook --config=~/.jupyter/my_custom_config.py\n",
    "```\n",
    "\n",
    "## B.6 结论\n",
    "\n",
    "当您阅读本书中的代码示例并提高作为Python程序员的技能时，我鼓励您继续学习IPython和Jupyter生态系统。由于这些项目旨在提高用户的工作效率，因此您可能会发现工具，这些工具比单独使用Python语言及其计算库使您更轻松地完成工作。\n",
    "\n",
    "您还可以在nbviewer网站上找到许多有趣的Jupyter笔记本。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
